use std::{rc::Rc, cell::RefCell, sync::Arc};

use crate::{instructions::base::{Instruction, BytecodeReader}, rtda::{heap::{ClassLoader, self}, Frame}};


pub const AT_BOOLEAN: u8 = 4;
pub const AT_CHAR: u8 = 5;
pub const AT_FLOAT: u8 = 6;
pub const AT_DOUBLE: u8 = 7;
pub const AT_BYTE: u8 = 8;
pub const AT_SHORT: u8 = 9;
pub const AT_INT: u8 = 10;
pub const AT_LONG: u8 = 11;

// 需要两个操作数。
// 第一个操作数是一个uint8整数，在字节码中紧跟在指令操作码后面，表示要创建哪种类型的数组。
// 第二个操作数是count，从操作数栈中弹出，表示数组长度。
#[derive(Debug, Default)]
pub struct NEW_ARRAY {
    atype: u8
}

impl Instruction for NEW_ARRAY {
    fn fetch_operands(&mut self, reader: &mut BytecodeReader) {
        self.atype = reader.read_u8();
    }

    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let count = stack.borrow_mut().pop_int();
        if count < 0 {
            panic!("java.lang.NegativeArraySizeException");
        }
        let class_loader = frame.borrow().get_method().get_class().get_class_loader().unwrap();
        let arr_class = get_primitive_array_class(&mut class_loader.lock().unwrap(), self.atype);
        let arr = heap::Class::new_array(arr_class, count as usize);
        stack.borrow_mut().push_ref(Some(Box::into_raw(Box::new(arr))));
    }
}

fn get_primitive_array_class(loader: &mut ClassLoader, atype: u8) -> Arc<heap::Class> {
    match atype {
        AT_BOOLEAN => loader.load_class("[Z".to_string()),
        AT_BYTE => loader.load_class("[B".to_string()),
        AT_CHAR => loader.load_class("[C".to_string()),
        AT_SHORT => loader.load_class("[S".to_string()),
        AT_INT => loader.load_class("[I".to_string()),
        AT_LONG => loader.load_class("[J".to_string()),
        AT_FLOAT => loader.load_class("[F".to_string()),
        AT_DOUBLE => loader.load_class("[D".to_string()),
        _ => panic!("Invalid atype!")
    }
}

